const axios = require('axios');
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
var EventEmitter = require('events').EventEmitter;
var localUpdater = function(url,ver,localRoot){
    this.realroot = this.url = typeof url == 'string' ? url : '';
    this.ver = typeof url == 'string' ? ver : '';
    this.localRoot = typeof url == 'string' ? localRoot : '';
    var event = new EventEmitter();
    this.on = event.on;
    this.emit = event.emit;
    this.file_list = [];
    this.newver = false;
    this.updating = false;
    var self = this;
    this.mkdirs = function(dirpath){
        if (fs.existsSync(dirpath) && fs.statSync(dirpath).isDirectory()) {
            return true;
        } else {
            if (self.mkdirs(path.dirname(dirpath))) {
                fs.mkdirSync(dirpath);
                return true;
            }
        }
    }
    this.checkUpdate = function(){
        if(self.updating){
            self.emit('updateError',{code:301,message:'update is running, please wait finished'});
            return false;
        }
        self.updating = true;
        axios({
            method: 'get',
            url: self.url + 'lastest.json',
            responseType: 'blob'
        }).then(function (response) {
            self.updating = false;
            if (response.status != 200) {
                self.emit('updateError', {code: 402, message: response.message});
                return false;
            }
            let data = JSON.parse(response.data);
            if (typeof data.version != 'string') {
                self.emit('updateError',{code:401,message:'response version is not a string'});
                return false;
            }
            if (self.ver != data.version) {
                self.newver = data.version;
                if (data.dir) {
                    if (data.dir.substr(0, 4) == 'http') {
                        self.realroot = data.dir
                    } else {
                        self.realroot += data.dir;
                    }
                }
                self.file_list = response.data.file_list;
                self.emit("updateAvilable",{ver:self.ver,newver:self.newver,file_list:self.file_list});
            }
            return true;
        }).catch(function(error){
            self.updating = false;
            self.emit('updateError',{code:403,message:error.message});
            return false;
        });
    }
    this.update = function(){
        if(!self.newver){
            self.emit('updateError',{code:302,message:'now is lastest version, no update'});
            return false;
        }
        if(self.file_list.length==0){
            self.emit('updateError',{code:303,message:'update file list is empty, no update'});
            return false;
        }
        self.updating = true;
        if (!(self.file_list instanceof Array)) {
            self.emit('updateError',{code:405,message:'update file list is error, file lsit is not Array'});
            return false;
        }
        for(var i=0;i<self.file_list.length;i++){
            //检查服务端文件信息
            if (typeof self.file_list[i].hash != 'string' || typeof self.file_list[i].hash != 'string') {
                continue;
            }
            (function(i){
                var filepath = self.localRoot + '/' + self.file_list[i].path;
                if (fs.existsSync(filepath)) {
                    //本地文件MD5验证,若MD5相同则无需更新
                    var buffer = fs.readFileSync(filepath);
                    var fsHash = crypto.createHash('md5');
                    fsHash.update(buffer);
                    var md5 = fsHash.digest('hex');
                    if (md5 == self.file_list[i].hash) {
                        return;
                    }
                }
                //递归检查创建目录
                self.mkdirs(path.dirname(filepath));
                axios({
                    method: 'get',
                    url: self.realroot + self.file_list[i].path,
                    responseType: 'blob'
                }).then(function (response) {
                    if(response.status == 200){
                        fs.writeFileSync(filepath, response.data, {encoding: 'binary'});
                        self.emit('updateFile',{path:self.file_list[i].path,hash:self.file_list[i].hash,index:i,counts:self.file_list.list});
                        if(i>=self.file_list.length-1){
                            self.emit('updateFinish',{ver:self.ver,newver:self.newver,file_list:self.file_list});
                            self.newver = false;
                        }
                    }else{
                        self.emit('updateError',{code:501,message:response.message,file:self.file_list[i]});
                    }
                }).catch(err => {
                    self.emit('updateError',{code:502,message:err.message,file:self.file_list[i]});
                });
                if(i>=self.file_list.length-1){
                    self.updating = false;
                }
            })(i);
        }
        return true;
    }
}

var makeList = function(dir, root ,version = '1.0.0'){
    let _self = this;
    this.filesList = [];
    this.readFileList = function(dir, root){
        const files = fs.readdirSync(path.join(root, dir));
        console.log(files);
        files.forEach((item, index) => {
            var fullPath = path.join(root, dir, item);
            const stat = fs.statSync(fullPath);
            if (stat.isDirectory()) {
                _self.readFileList(path.join(dir, item),root);  //递归读取文件
            } else {
                var buffer = fs.readFileSync(fullPath);
                var fsHash = crypto.createHash('md5');
                fsHash.update(buffer);
                _self.filesList.push({path:path.join(dir, item),hash:fsHash.digest('hex')});
            }
        });
        return true;
    }
    this.readFileList(dir,root);
    var lastest = JSON.stringify({
        version:version,
        dir:root,
        file_list:_self.filesList
    });
    fs.writeFileSync('./lastest.json',lastest,{type:'utf-8'});
}

module.exports = localUpdater;
module.exports.makeList = makeList;